We are migrating the bug tracker to github Issues. This is now the preferred way to report NASM bugs.

Self-registration is disabled due to spam issue (mail gorcunov@gmail.com or hpa@zytor.com to create an account)

Bug 3392602 - git nasm: segmentation fault when assembling lmacros tests
Summary: git nasm: segmentation fault when assembling lmacros tests
Status: RESOLVED FIXED
Alias: None
Product: NASM
Classification: Unclassified
Component: Assembler (show other bugs)
Version: 2.15.xx
Hardware: Other x86 Linux
: Medium blocker
Assignee: nobody
URL:
Depends on:
Blocks:
 
Reported: 2019-08-10 06:34 PDT by E. C. Masloch
Modified: 2019-08-21 10:04 PDT (History)
6 users (show)

Obtained from: Built from git using configure
Generated by: ---
Bug category:
Observed for: ---
Regression: ---
Regression since:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description E. C. Masloch 2019-08-10 06:34:31 PDT
On a Debian Stretch (Debian 9) server, building any lmacros tests with nasm-2.14.03rc2-371-g6686de2b seems to always crash. The crash does not occur if I do not specify a needed -I switch.

$ nasm 001.asm -I ../                                                            Segmentation fault (core dumped)
$ nasm 001.asm
001.asm:2: fatal: unable to open include file `lmacros2.mac'
$ nasm 016.asm -I ../
Segmentation fault (core dumped)
$ nasm 016.asm
016.asm:2: fatal: unable to open include file `lmacros2.mac'
$ 

This is running in the tests/ subdirectory of https://bitbucket.org/ecm/lmacros/src/44c3a480632df5887e825d6372d8ecc28f9bd0be/

A very simple test file succeeds:

$ cat test.asm
%include "test.mac"

db TEST
$ cat test.mac
%define TEST 26h
$ nasm -v
NASM version 2.15rc0 compiled on Aug 10 2019
$ nasm test.asm
$ 

Including just lmacros3.mac also succeeds:

$ nasm -v
NASM version 2.15rc0 compiled on Aug 10 2019
$ cat test.asm
%include "lmacros3.mac"

nop
$ nasm test.asm
test.asm:1: fatal: unable to open include file `lmacros3.mac'
$ nasm test.asm -I ../
$
Comment 1 E. C. Masloch 2019-08-10 06:45:50 PDT
Here's the listing output witn -Lp, the crash leaves an empty (but existing) file:

$ nasm 001.asm -l 001.lst -Lp
001.asm:2: fatal: unable to open include file `lmacros2.mac'
$ cat 001.lst
     1
     2                                  %include "lmacros2.mac"
     2          XXXXXXXXXXXXXXXXXX       fatal: unable to open include file `lmacro
s2.mac'
$ nasm 001.asm -l 001.lst -Lp -I ../
Segmentation fault (core dumped)
$ cat 001.lst
$
Comment 2 E. C. Masloch 2019-08-10 07:11:32 PDT
Minimal test case that fails:

$ nasm -v
NASM version 2.15rc0 compiled on Aug 10 2019
$ cat test.asm

%include "lmacros2.mac"


        call fun1

fun1:
$ nasm test.asm -I ../
Segmentation fault (core dumped)
$
Comment 3 E. C. Masloch 2019-08-10 07:14:07 PDT
Even without the label, the crash occurs (and without an error about undefined symbol):



$ cat test.asm

%include "lmacros2.mac"


        call fun1
$ nasm test.asm -I ../
Segmentation fault (core dumped)
$
Comment 4 Ozkan Sezer 2019-08-10 07:23:21 PDT
With gdb:
Program received signal SIGSEGV, Segmentation fault.
0x08058587 in pp_list_one_macro (m=0x819a268, severity=129571) at asm/preproc.c:5862
5862	    pp_list_one_macro(m->next_active, severity);
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6_10.3.i686
(gdb) bt
#0  0x08058587 in pp_list_one_macro (m=0x819a268, severity=129571) at asm/preproc.c:5862
(seems to have stuck in there recursing infinitely?)

With valgrind:
==27518== Stack overflow in thread 1: can't grow stack to 0xbe590fec
==27518== 
==27518== Process terminating with default action of signal 11 (SIGSEGV)
==27518==  Access not within mapped region at address 0xBE590FEC
==27518==    at 0x8058587: pp_list_one_macro (preproc.c:5862)
==27518==  If you believe this happened as a result of a stack
==27518==  overflow in your program's main thread (unlikely but
==27518==  possible), you can try to increase the size of the
==27518==  main thread stack using the --main-stacksize= flag.
==27518==  The main thread stack size used in this run was 10485760.
==27518== Stack overflow in thread 1: can't grow stack to 0xbe590fe8
==27518== 
==27518== Process terminating with default action of signal 11 (SIGSEGV)
==27518==  Access not within mapped region at address 0xBE590FE8
==27518==    at 0x40014BA: _vgnU_freeres (vg_preloaded.c:58)
==27518==  If you believe this happened as a result of a stack
==27518==  overflow in your program's main thread (unlikely but
==27518==  possible), you can try to increase the size of the
==27518==  main thread stack using the --main-stacksize= flag.
==27518==  The main thread stack size used in this run was 10485760.
==27518== 
==27518== HEAP SUMMARY:
==27518==     in use at exit: 5,664,587 bytes in 200,288 blocks
==27518==   total heap usage: 237,526 allocs, 37,238 frees, 7,086,183 bytes allocated
Comment 5 E. C. Masloch 2019-08-10 08:12:27 PDT
The recursing infinitely bit alerted me to the fact that it may be my "call" macro, so here's a minimal test case:

$ nasm -v
NASM version 2.15rc0 compiled on Aug 10 2019
$ cat test.asm
                ; Call with word parameters behind opcode
        %imacro call 1-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro


        call fun1
$ nasm test.asm
Segmentation fault (core dumped)
$
Comment 6 E. C. Masloch 2019-08-10 08:17:12 PDT
Changing the macro to 2-* allows building my tests. However, I do think this is a regression and thus should work with 1-*.
Comment 7 H. Peter Anvin 2019-08-15 19:29:34 PDT
Fix checked in. This test case was extremely useful, thanks!

(Note: there is still another bug affecting lmacros; I will look at that next.)
Comment 8 H. Peter Anvin 2019-08-15 19:33:44 PDT
Nevermind. It looks like warning for warn_struc_at 64 on line 16 of testsat.asm is actually correct. So I'm going to assume that everything is OK with lmacros now.

Thank you *so much* for the very useful bug report!
Comment 9 E. C. Masloch 2019-08-20 05:10:02 PDT
I did a few more tests with three different NASM versions. The good news is that all of them are consistent and my original source just works. However, it seems to be slower than the alternative, which is using 2-* for the macro parameters and disabling the macro-params (later macro-params-multi) warning:

$ cat test.asm
%ifdef P2
                ; Call with word parameters behind opcode
        %imacro call 2-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
%warning p2
%else
                ; Call with word parameters behind opcode
        %imacro call 1-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
%warning p1
%endif

%ifndef REPEAT
 %assign REPEAT 100_000
%endif


        cpu 386
        bits 32
        org 0

%rep REPEAT
        call alpha
        call beta
        call gamma
        call delta
%endrep

alpha:
        nop
        nop
        nop
beta:
        nop
        nop
        nop
gamma:
        nop
        nop
        nop
delta:
        nop
        nop
        nop

$ oldnasm -v
NASM version 2.15rc0 compiled on Dec 28 2018
$ time oldnasm test.asm -Wno-macro-params -DP2
test.asm:10: warning: p2 [-w+user]

real    0m2.429s
user    0m2.406s
sys     0m0.008s
$ time oldnasm test.asm -Wno-macro-params
test.asm:20: warning: p1 [-w+user]

real    0m9.497s
user    0m7.906s
sys     0m0.802s
$ time oldnasm test.asm -DREPEAT=1 -DP2
test.asm:10: warning: p2 [-w+user]
test.asm:37: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:37: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:37: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:37: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]

real    0m0.006s
user    0m0.002s
sys     0m0.003s
$ time oldnasm test.asm -DREPEAT=1
test.asm:20: warning: p1 [-w+user]

real    0m0.012s
user    0m0.003s
sys     0m0.002s
$ /usr/bin/nasm -v
NASM version 2.12.01
$ time /usr/bin/nasm test.asm -Wno-macro-params -DP2

real    0m2.238s
user    0m2.225s
sys     0m0.007s
$ time /usr/bin/nasm test.asm -Wno-macro-params

real    0m6.745s
user    0m6.726s
sys     0m0.005s
$ time /usr/bin/nasm test.asm -DREPEAT=1 -DP2
test.asm:37: warning: macro `call' exists, but not taking 1 parameters
test.asm:37: warning: macro `call' exists, but not taking 1 parameters
test.asm:37: warning: macro `call' exists, but not taking 1 parameters
test.asm:37: warning: macro `call' exists, but not taking 1 parameters

real    0m0.006s
user    0m0.001s
sys     0m0.005s
$ time /usr/bin/nasm test.asm -DREPEAT=1

real    0m0.004s
user    0m0.001s
sys     0m0.003s
$ nasm -v
NASM version 2.15rc0 compiled on Aug 20 2019
$ time nasm test.asm -Wno-macro-params -DP2
test.asm:10: warning: p2 [-w+user]

real    0m2.520s
user    0m2.510s
sys     0m0.006s
$ time nasm test.asm -Wno-macro-params
test.asm:20: warning: p1 [-w+user]

real    0m14.976s
user    0m9.204s
sys     0m1.168s
$ time nasm test.asm -DREPEAT=1 -DP2
test.asm:10: warning: p2 [-w+user]
test.asm:37: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:37: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:37: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:37: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]

real    0m0.006s
user    0m0.002s
sys     0m0.003s
$ time nasm test.asm -DREPEAT=1
test.asm:20: warning: p1 [-w+user]

real    0m0.004s
user    0m0.001s
sys     0m0.002s
$
Comment 10 E. C. Masloch 2019-08-21 10:04:13 PDT
Did some more tests:

(nasm is https://repo.or.cz/nasm.git/commitdiff/7eb18213b78f06b45c85e2b224613cce4a20304b )


$ nasm -v
NASM version 2.15rc0 compiled on Aug 21 2019
$ ./tes.sh 0 nasm -DREPEAT=1 -DPARAM2
nasm test.asm -DP1 -DREPEAT=1 -DPARAM2
test.asm:38: warning: case p1 [-w+user]
nasm test.asm -DP2 -DREPEAT=1 -DPARAM2
test.asm:28: warning: case p2 [-w+user]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
nasm test.asm -DP3 -DREPEAT=1 -DPARAM2
test.asm:15: warning: case p3 [-w+user]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
test.asm:69: warning: multi-line macro `call' exists, but not taking 1 parameter [-w+macro-params-multi]
nasm test.asm -DP4 -DREPEAT=1 -DPARAM2
test.asm:2: warning: case p4 [-w+user]


p3 with the call 2-* definition then call 1 causes the warnings about non-matching mmacro. p4 (which reverses the definitions to call 1 then call 2-*) does not cause these warnings.


$ ./tes.sh 1 nasm -DPARAM2 -w-macro-params
time nasm test.asm -DP1 -DPARAM2 -w-macro-params
test.asm:38: warning: case p1 [-w+user]

real    0m10.176s
user    0m9.349s
sys     0m0.797s
time nasm test.asm -DP2 -DPARAM2 -w-macro-params
test.asm:28: warning: case p2 [-w+user]

real    0m5.739s
user    0m5.460s
sys     0m0.221s
time nasm test.asm -DP3 -DPARAM2 -w-macro-params
test.asm:15: warning: case p3 [-w+user]

real    0m7.264s
user    0m6.996s
sys     0m0.254s
time nasm test.asm -DP4 -DPARAM2 -w-macro-params
test.asm:2: warning: case p4 [-w+user]

real    0m7.427s
user    0m7.133s
sys     0m0.269s


p1 (call 1-*) takes the longest, p2 (only call 2-*) is the fastest (but causes the warnings when not suppressed), p3 and p4 are about equal.


$ oldnasm -v
NASM version 2.15rc0 compiled on Dec 28 2018
$ ./tes.sh 0 oldnasm -DREPEAT=1 -DPARAM2
oldnasm test.asm -DP1 -DREPEAT=1 -DPARAM2
test.asm:38: warning: case p1 [-w+user]
oldnasm test.asm -DP2 -DREPEAT=1 -DPARAM2
test.asm:28: warning: case p2 [-w+user]
test.asm:69: warning: (call:1) macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:69: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:69: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
test.asm:69: warning: macro `call' exists, but not taking 1 parameters [-w+macro-params]
oldnasm test.asm -DP3 -DREPEAT=1 -DPARAM2
test.asm:15: warning: case p3 [-w+user]
oldnasm test.asm -DP4 -DREPEAT=1 -DPARAM2
test.asm:2: warning: case p4 [-w+user]


This does not cause warnings for either p3 or p4.


$ ./tes.sh 1 oldnasm -DPARAM2 -w-macro-params
time oldnasm test.asm -DP1 -DPARAM2 -w-macro-params
test.asm:38: warning: case p1 [-w+user]

real    0m9.304s
user    0m8.563s
sys     0m0.728s
time oldnasm test.asm -DP2 -DPARAM2 -w-macro-params
test.asm:28: warning: case p2 [-w+user]

real    0m4.961s
user    0m4.743s
sys     0m0.203s
time oldnasm test.asm -DP3 -DPARAM2 -w-macro-params
test.asm:15: warning: case p3 [-w+user]

real    0m5.905s
user    0m5.690s
sys     0m0.191s
time oldnasm test.asm -DP4 -DPARAM2 -w-macro-params
test.asm:2: warning: case p4 [-w+user]

real    0m5.887s
user    0m5.700s
sys     0m0.181s


The timing is roughly the same for all cases! The times are slightly shorter though.


$ /usr/bin/nasm -v
NASM version 2.12.01
$ ./tes.sh 0 /usr/bin/nasm -DREPEAT=1 -DPARAM2
/usr/bin/nasm test.asm -DP1 -DREPEAT=1 -DPARAM2
/usr/bin/nasm test.asm -DP2 -DREPEAT=1 -DPARAM2
test.asm:69: warning: (call:1) macro `call' exists, but not taking 1 parameters
test.asm:69: warning: macro `call' exists, but not taking 1 parameters
test.asm:69: warning: macro `call' exists, but not taking 1 parameters
test.asm:69: warning: macro `call' exists, but not taking 1 parameters
/usr/bin/nasm test.asm -DP3 -DREPEAT=1 -DPARAM2
/usr/bin/nasm test.asm -DP4 -DREPEAT=1 -DPARAM2


Again p3 and p4 both do not cause any warnings. (So, the git nasm's warnings for p3 are regressions.) p2 causes a warning even for the "%? %1" call in the 2-* macro.


$ ./tes.sh 1 /usr/bin/nasm -DPARAM2 -w-macro-params
time /usr/bin/nasm test.asm -DP1 -DPARAM2 -w-macro-params

real    0m8.540s
user    0m8.510s
sys     0m0.007s
time /usr/bin/nasm test.asm -DP2 -DPARAM2 -w-macro-params

real    0m4.344s
user    0m4.329s
sys     0m0.005s
time /usr/bin/nasm test.asm -DP3 -DPARAM2 -w-macro-params

real    0m6.357s
user    0m6.337s
sys     0m0.008s
time /usr/bin/nasm test.asm -DP4 -DPARAM2 -w-macro-params

real    0m5.912s
user    0m5.897s
sys     0m0.007s


The timing is relatively the same.


$ cat tes.sh
#! /bin/bash

usetime="$1"
shift

asm="$1"
shift

if (( "$usetime" )); then {
        echo time "$asm" test.asm -DP1 "$@"
        time "$asm" test.asm -DP1 "$@"
        echo time "$asm" test.asm -DP2 "$@"
        time "$asm" test.asm -DP2 "$@"
        echo time "$asm" test.asm -DP3 "$@"
        time "$asm" test.asm -DP3 "$@"
        echo time "$asm" test.asm -DP4 "$@"
        time "$asm" test.asm -DP4 "$@"
} fi

if (( "$usetime" == 0 )); then {
        echo "$asm" test.asm -DP1 "$@"
        "$asm" test.asm -DP1 "$@"
        echo "$asm" test.asm -DP2 "$@"
        "$asm" test.asm -DP2 "$@"
        echo "$asm" test.asm -DP3 "$@"
        "$asm" test.asm -DP3 "$@"
        echo "$asm" test.asm -DP4 "$@"
        "$asm" test.asm -DP4 "$@"
} fi
$ cat test.asm
%ifdef P4
%warning case p4
        %imacro call 1.nolist
                %? %1
        %endmacro
                ; Call with word parameters behind opcode
        %imacro call 2-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
%elifdef P3
%warning case p3
                ; Call with word parameters behind opcode
        %imacro call 2-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
        %imacro call 1.nolist
                %? %1
        %endmacro
%elifdef P2
%warning case p2
                ; Call with word parameters behind opcode
        %imacro call 2-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
%else
%warning case p1
                ; Call with word parameters behind opcode
        %imacro call 1-*.nolist
                %? %1
%rep %0 - 1
%rotate 1
                dw %1
%endrep
        %endmacro
%endif

%ifndef REPEAT
 %assign REPEAT 100_000
%endif

%ifndef PARAM1
 %define PARAM1 , 26h
%endif
%ifndef PARAM2
 %define PARAM2 , 26h
%endif

        cpu 386
        bits 32
        org 0

%rep REPEAT
        call alpha PARAM1
        call beta PARAM2
        call gamma PARAM2
        call delta PARAM2
%endrep

alpha:
        nop
        nop
        nop
beta:
        nop
        nop
        nop
gamma:
        nop
        nop
        nop
delta:
        nop
        nop
        nop

$